import random
import subprocess
import os
import argparse
import shutil
import logging
from multiprocessing import Pool
from typing import List, Tuple

class VideoObfuscator:
    """视频干扰处理工具，用于在不影响观感的情况下干扰查重检测"""
    
    def __init__(self):
        self.logger = self._setup_logger()
        self.temp_dir = "tmp_video_obfuscator"
        
        # 配置参数
        self.segment_params = {
            'min_duration': 2.0,
            'max_duration': 6.0,
            'min_speed': 0.95,
            'max_speed': 1.1,
            'min_volume': 0.8,
            'max_volume': 1.2,
            'min_noise': 0.005,
            'max_noise': 0.015,
            'noise_types': ['pink', 'brown', 'blue', 'violet']
        }
        
        self.subtle_params = {
            'brightness_range': (-0.02, 0.02),
            'contrast_range': (0.99, 1.01),
            'saturation_range': (0.99, 1.01),
            'noise_strengths': [1, 2],
            'pts_offset_range': (0.0005, 0.002),
            'audio_delay': "1|1",
            'output_fps_range': (18, 28)
        }

    def _setup_logger(self) -> logging.Logger:
        """配置日志记录器"""
        logger = logging.getLogger(__name__)
        logger.setLevel(logging.INFO)
        handler = logging.StreamHandler()
        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        return logger

    def _run_command(self, cmd: List[str]) -> bool:
        """执行命令并处理错误"""
        try:
            self.logger.debug(f"执行命令: {' '.join(cmd)}")
            subprocess.run(cmd, check=True, stderr=subprocess.PIPE)
            return True
        except subprocess.CalledProcessError as e:
            self.logger.error(f"命令执行失败: {e.stderr.decode().strip()}")
            return False

    def _get_video_duration(self, video_path: str) -> float:
        """获取视频时长(秒)"""
        cmd = [
            'ffprobe', '-v', 'error',
            '-show_entries', 'format=duration',
            '-of', 'default=noprint_wrappers=1:nokey=1',
            video_path
        ]
        try:
            result = subprocess.run(cmd, capture_output=True, text=True, check=True)
            return float(result.stdout.strip())
        except subprocess.CalledProcessError as e:
            self.logger.error(f"获取视频时长失败: {e.stderr}")
            raise RuntimeError("无法获取视频时长")

    def _generate_segments(self, video_path: str, duration: float) -> Tuple[List[str], List[tuple]]:
        """生成视频分段信息"""
        segments = []
        segment_files = []
        current_time = 0.0
        segment_index = 0

        while current_time < duration:
            interval = random.uniform(
                self.segment_params['min_duration'],
                self.segment_params['max_duration']
            )
            next_time = min(current_time + interval, duration)

            segment_info = (
                current_time, next_time, video_path,
                random.uniform(self.segment_params['min_speed'], self.segment_params['max_speed']),
                random.uniform(self.segment_params['min_volume'], self.segment_params['max_volume']),
                random.uniform(self.segment_params['min_noise'], self.segment_params['max_noise']),
                f"segment_{segment_index}.mp4"
            )
            
            segments.append(segment_info)
            segment_files.append(segment_info[-1])
            current_time = next_time
            segment_index += 1

        return segment_files, segments

    def _process_segment(self, segment_info: tuple) -> bool:
        """处理单个视频片段"""
        current_time, next_time, input_path, speed, volume, noise, output_file = segment_info
        
        # 临时文件路径
        temp_output = os.path.join(self.temp_dir, f"temp_{output_file}")
        final_output = os.path.join(self.temp_dir, output_file)

        # 基本处理：变速、音量、噪声
        base_cmd = [
            'ffmpeg',
            '-ss', str(current_time),
            '-to', str(next_time),
            '-i', input_path,
            '-filter_complex',
            f'[0:v]setpts={1/speed}*PTS[v];'
            f'[0:a]atempo={speed},volume={volume}[a1];'
            f'anoisesrc=c=1:a={noise}:color={random.choice(self.segment_params["noise_types"])}[a2];'
            f'[a1][a2]amix=inputs=2:duration=first:dropout_transition=0[a]',
            '-map', '[v]',
            '-map', '[a]',
            '-c:v', 'libx264',
            '-preset', 'fast',
            temp_output
        ]
        
        if not self._run_command(base_cmd):
            return False

        # 应用不易察觉的修改
        subtle_cmd = [
            'ffmpeg',
            '-i', temp_output,
            '-vf', (
                f'eq=brightness={random.uniform(*self.subtle_params["brightness_range"])}:'
                f'contrast={random.uniform(*self.subtle_params["contrast_range"])}:'
                f'saturation={random.uniform(*self.subtle_params["saturation_range"])},'
                f'noise=c0s={random.choice(self.subtle_params["noise_strengths"])}:allf=t,'
                f'setpts=PTS+{random.uniform(*self.subtle_params["pts_offset_range"])}*random(1),'
                'crop=iw-1:ih-1:0:0,scale=iw:ih'
            ),
            '-af', f'adelay={self.subtle_params["audio_delay"]}',
            '-c:v', 'libx264',
            '-preset', 'fast',
            '-c:a', 'aac',
            final_output
        ]
        
        success = self._run_command(subtle_cmd)
        if os.path.exists(temp_output):
            os.remove(temp_output)
        return success

    def _merge_segments(self, segment_files: List[str], output_path: str) -> bool:
        """合并所有视频片段"""
        list_file = os.path.join(self.temp_dir, 'segments.txt')
        with open(list_file, 'w') as f:
            for segment in segment_files:
                f.write(f"file '{segment}'\n")

        output_fps = random.randint(*self.subtle_params['output_fps_range'])
        merge_cmd = [
            'ffmpeg',
            '-y',
            '-f', 'concat',
            '-safe', '0',
            '-i', list_file,
            '-vf', f'fps={output_fps}',
            '-c:v', 'libx264',
            '-preset', 'fast',
            '-c:a', 'aac',
            output_path
        ]
        return self._run_command(merge_cmd)

    def process_video(self, input_path: str, output_path: str) -> bool:
        """处理视频主函数"""
        try:
            # 创建临时目录
            if not os.path.exists(self.temp_dir):
                os.makedirs(self.temp_dir)

            # 获取视频信息
            duration = self._get_video_duration(input_path)
            self.logger.info(f"视频总时长: {duration:.2f}秒")

            # 生成分段
            segment_files, segments = self._generate_segments(input_path, duration)
            self.logger.info(f"将视频分成 {len(segments)} 个片段进行处理")

            # 多进程处理
            with Pool() as pool:
                results = pool.map(self._process_segment, segments)
                if not all(results):
                    self.logger.error("部分片段处理失败")
                    return False

            # 合并片段
            self.logger.info("开始合并视频片段...")
            if not self._merge_segments(segment_files, output_path):
                return False

            self.logger.info(f"视频处理完成: {output_path}")
            return True

        except Exception as e:
            self.logger.error(f"处理过程中发生错误: {str(e)}")
            return False
        finally:
            # 清理临时文件
            if os.path.exists(self.temp_dir):
                shutil.rmtree(self.temp_dir)
                self.logger.info("已清理临时文件")

def main():
    parser = argparse.ArgumentParser(description='视频干扰处理工具')
    parser.add_argument('input_video', help='输入视频路径')
    parser.add_argument('output_video', help='输出视频路径')
    args = parser.parse_args()

    processor = VideoObfuscator()
    if processor.process_video(args.input_video, args.output_video):
        print("处理成功完成")
    else:
        print("处理过程中出现错误")

if __name__ == "__main__":
    main()